package dataStructure;
import java.lang.reflect.InvocationTargetException;

public class LinkedList<DataT> {
	private ListNode<DataT> first;
	private ListNode<DataT> last;
	private int length;
	
	public LinkedList() {
		first=null;
		last=null;
		this.length=0;
	}
	
	public void addNode(ListNode<DataT> newNode){
		if(first==null){
			first=newNode;
			last=first;
		} else {
			ListNode<DataT> temp=last;
			last.setNext(newNode);
			last=newNode;
			last.setPrevious(temp);
		}

		this.length++;
	}
	
	public void addContent(DataT content){
		ListNode<DataT> newNode =  new ListNode<DataT> (content);
		this.addNode(newNode);
	}
	
	//For Debugging
	public void printList() throws IllegalAccessException, IllegalArgumentException, InvocationTargetException, NoSuchMethodException, SecurityException{
		ListNode<DataT> temp=this.first;
		while(temp!=null){
			temp.printContent();
			temp=temp.getNext();
		}
	}

	public LinkedList<DataT> searchNodes(String field, String value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NullPointerException {
		LinkedList<DataT> resultList =new LinkedList<DataT>();
		ListNode<DataT> temp=this.first;
		while(temp!=null){
			Object result=temp.getAttrVal(field);
			if(value.equals(result.toString())){
				ListNode<DataT> newSearchResult=temp;//ListNode is very small, the actual content is stored as a Pointer only.
				resultList.addNode(newSearchResult);
			}
			temp=temp.next;
		}
		return resultList;
	}

	public DataT searchContent(String field, String value) throws NoSuchFieldException, SecurityException, IllegalArgumentException, IllegalAccessException, NoSuchMethodException, InvocationTargetException, NullPointerException {
		ListNode<DataT> temp=this.first;
		while(temp!=null){
			Object result=temp.getAttrVal(field);
			if(result != null){
				if(value.equals(result.toString())){
					return temp.getContent();
				}
			}
			temp=temp.next;
		}
		return null;
	}
	
	public boolean removeNode(DataT node){
		ListNode<DataT> temp=this.first;
		while(temp!=null){
			if(temp.getContent().equals(node)){
				if(temp.previous!=null)
					temp.previous.next=temp.next;
				if(temp.next!=null)
					temp.next.previous=temp.previous;
				
				temp=null;
				this.length--;
				return true;
			}
			temp=temp.next;
		}
		return false;
	}
	
	public boolean insertNode(DataT node){
		
		this.length++;
		
		return true;
	}
	
	public Object get(int n){
		ListNode<DataT> temp=this.first;
		for(int i=0;i<n;i++){
			temp=temp.next;
		}
		
		return temp.getContent();
	}

	public int getLength() {
		return length;
	}

	public void setLength(int length) {
		this.length = length;
	}

	public ListNode<DataT> getFirstNode() {
		return this.first;
	}

	public void setFirstNode(ListNode<DataT> first) {
		this.first = first;
	}

	public ListNode<DataT> getLastNode() {
		return this.last;
	}

	public void setLastNode(ListNode<DataT> last) {
		this.last = last;
	}

	public DataT getLastNodeContent() {
		return this.getLastNode().getContent();
	}

	public DataT getFirstNodeContent() {
		//Not done, what is first node is null? or content is null
		return this.getFirstNode().getContent();
	}
}
